package com.smart.community.region.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.smart.community.commons.utils.SecurityUtils;
import com.smart.community.feign.property.service.DataScopeFeign;
import com.smart.community.commons.cache.DataScopeInfo;
import com.smart.community.region.dto.BatchGenerateFeeRecordDTO;
import com.smart.community.region.dto.ShopFeeRecordDTO;
import com.smart.community.region.entity.ShopFeeRecord;
import com.smart.community.region.mapper.ShopFeeRecordMapper;
import com.smart.community.region.service.IShopFeeRecordService;
import com.smart.community.region.service.IShopService;
import com.smart.community.region.entity.Shop;
import com.smart.community.region.vo.ShopFeeRecordVO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import io.seata.spring.annotation.GlobalTransactional;
import org.springframework.util.CollectionUtils;

import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 店铺费用记录Service实现类
 * 遵循《Java后端SpringBoot代码开发规范_重构版.md》Service层规范
 * 遵循《系统状态枚举权威标准声明.md》状态枚举规范
 * 
 * @author Wu.Liang
 * @version 1.0.0
 * @since 2025-01-30
 */
@Slf4j
@Service
public class ShopFeeRecordServiceImpl extends ServiceImpl<ShopFeeRecordMapper, ShopFeeRecord> 
        implements IShopFeeRecordService {
    
    @Autowired
    private DataScopeFeign dataScopeFeign;
    
    @Autowired
    private IShopService shopService;
    
    /**
     * 分页查询费用记录
     * 遵循《Java后端SpringBoot代码开发规范_重构版.md》Service层规范
     * 遵循《系统状态枚举权威标准声明.md》状态枚举规范
     */
    @Override
    @Cacheable(value = "feeRecord:page", key = "#current + '_' + #size + '_' + #shopId + '_' + #feeType + '_' + #paymentStatus + '_' + #feeDateStart + '_' + #feeDateEnd + '_' + #dueDateStart + '_' + #dueDateEnd")
    public Object getFeeRecordPage(Integer current, Integer size, Long shopId, String feeType, Integer paymentStatus,
            String feeDateStart, String feeDateEnd, String dueDateStart, String dueDateEnd) throws Exception {
        log.info("分页查询费用记录，当前页: {}, 每页大小: {}, 店铺ID: {}, 费用类型: {}, 支付状态: {}, 费用日期: {} - {}, 到期日期: {} - {}", 
                current, size, shopId, feeType, paymentStatus, feeDateStart, feeDateEnd, dueDateStart, dueDateEnd);
        
        try {
            // 获取当前用户ID
            Long currentUserId = SecurityUtils.getCurrentUserId();
            if (currentUserId == null) {
                log.warn("用户未登录，无法查询费用记录");
                return createEmptyPageResult(current, size);
            }
            
            // 获取用户数据权限范围
            DataScopeInfo userDataScope = dataScopeFeign.getUserDataScope(currentUserId);
            if (userDataScope == null) {
                log.warn("获取用户数据权限范围失败，用户ID：{}，返回空结果", currentUserId);
                return createEmptyPageResult(current, size);
            }
            
            log.info("用户数据权限信息：用户ID={}, 是否超级管理员={}, 是否物业公司用户={}, 社区ID列表={}", 
                currentUserId, userDataScope.isSuperAdmin(), userDataScope.isPropertyCompanyUser(), userDataScope.getCommunityIds());
            
            // 使用自定义Mapper方法查询包含店铺名称的数据
            Page<ShopFeeRecordVO> page = new Page<>(current, size);
            IPage<ShopFeeRecordVO> result;
            
            // 超级管理员，可以查看所有数据
            if (userDataScope.isSuperAdmin()) {
                log.info("用户{}为超级管理员，可以查看所有费用记录", currentUserId);
                result = baseMapper.selectFeeRecordVOPage(page, shopId, feeType, paymentStatus, feeDateStart, feeDateEnd, dueDateStart, dueDateEnd);
            } else {
                // 物业公司用户，只查询关联社区的店铺费用记录
                List<Long> communityIds = userDataScope.getCommunityIds();
                if (communityIds == null || communityIds.isEmpty()) {
                    log.warn("用户{}无权限访问任何社区数据，返回空结果", currentUserId);
                    return createEmptyPageResult(current, size);
                }
                
                // 根据社区ID列表查询店铺ID列表
                List<Long> shopIds = getShopIdsByCommunityIds(communityIds);
                if (shopIds.isEmpty()) {
                    log.warn("用户{}关联的社区{}中没有店铺数据，返回空结果", currentUserId, communityIds);
                    return createEmptyPageResult(current, size);
                }
                
                // 使用带权限过滤的查询方法
                result = baseMapper.selectFeeRecordVOPageWithPermission(page, shopId, feeType, paymentStatus, shopIds, feeDateStart, feeDateEnd, dueDateStart, dueDateEnd);
                log.info("用户{}数据权限过滤完成，可访问店铺数量：{}，店铺IDs：{}", currentUserId, shopIds.size(), shopIds);
            }
            
            log.info("分页查询费用记录成功，总数: {}", result.getTotal());
            return result;
            
        } catch (Exception e) {
            log.error("分页查询费用记录失败，当前页: {}, 每页大小: {}, 店铺ID: {}, 费用类型: {}, 支付状态: {}, 费用日期: {} - {}, 到期日期: {} - {}", 
                    current, size, shopId, feeType, paymentStatus, feeDateStart, feeDateEnd, dueDateStart, dueDateEnd, e);
            throw new Exception("分页查询费用记录失败: " + e.getMessage());
        }
    }
    
    /**
     * 根据ID获取费用记录详情
     * 遵循《Java后端SpringBoot代码开发规范_重构版.md》Service层规范
     */
    @Override
    @Cacheable(value = "feeRecord:detail", key = "#id")
    public ShopFeeRecordVO getFeeRecordDetail(Long id) throws Exception {
        log.info("获取费用记录详情，ID: {}", id);
        
        try {
            ShopFeeRecordVO result = baseMapper.selectFeeRecordDetail(id);
            if (result == null) {
                throw new Exception("费用记录不存在");
            }
            
            log.info("获取费用记录详情成功，ID: {}", id);
            return result;
            
        } catch (Exception e) {
            log.error("获取费用记录详情失败，ID: {}", id, e);
            throw new Exception("获取费用记录详情失败: " + e.getMessage());
        }
    }
    
    /**
     * 创建费用记录
     * 遵循《Java后端SpringBoot代码开发规范_重构版.md》Service层规范
     */
    @Override
    @GlobalTransactional(rollbackFor = Exception.class)
    @CacheEvict(value = {"feeRecord:page", "feeRecord:detail"}, allEntries = true)
    public Long createFeeRecord(ShopFeeRecordDTO dto) throws Exception {
        log.info("创建费用记录，店铺ID: {}, 费用类型: {}, 费用金额: {}", 
                dto.getShopId(), dto.getFeeType(), dto.getFeeAmount());
        
        try {
            // 构建费用记录实体
            ShopFeeRecord feeRecord = new ShopFeeRecord();
            BeanUtils.copyProperties(dto, feeRecord);
            
            // 设置创建人
            Long currentUserId = SecurityUtils.getCurrentUserId();
            feeRecord.setCreateBy(currentUserId);
            feeRecord.setUpdateBy(currentUserId);
            
            // 保存费用记录
            boolean success = save(feeRecord);
            if (!success) {
                throw new Exception("保存费用记录失败");
            }
            
            log.info("创建费用记录成功，ID: {}", feeRecord.getId());
            return feeRecord.getId();
            
        } catch (Exception e) {
            log.error("创建费用记录失败，店铺ID: {}, 费用类型: {}, 费用金额: {}", 
                    dto.getShopId(), dto.getFeeType(), dto.getFeeAmount(), e);
            throw new Exception("创建费用记录失败: " + e.getMessage());
        }
    }
    
    /**
     * 批量生成费用记录
     * 遵循《Java后端SpringBoot代码开发规范_重构版.md》Service层规范
     */
    @Override
    @GlobalTransactional(rollbackFor = Exception.class)
    @CacheEvict(value = {"feeRecord:page", "feeRecord:detail"}, allEntries = true)
    public Object batchGenerateFeeRecords(BatchGenerateFeeRecordDTO dto) throws Exception {
        log.info("批量生成费用记录，店铺数量: {}, 费用类型: {}, 生成月份: {}, 生成方式: {}", 
                dto.getShopIds().size(), dto.getFeeType(), dto.getBatchMonth(), dto.getBatchMode());
        
        try {
            List<Long> generatedIds = new ArrayList<>();
            int successCount = 0;
            int failCount = 0;
            
            // 解析生成月份
            LocalDate monthStart = LocalDate.parse(dto.getBatchMonth() + "-01");
            LocalDate monthEnd = monthStart.withDayOfMonth(monthStart.lengthOfMonth());
            
            for (Long shopId : dto.getShopIds()) {
                try {
                    // 获取店铺的费用标准
                    BigDecimal feeAmount = getFeeAmountForShop(shopId, dto.getFeeType(), dto.getBatchMode(), dto.getCustomAmount());
                    
                    if (feeAmount == null || feeAmount.compareTo(BigDecimal.ZERO) <= 0) {
                        log.warn("店铺{}没有找到有效的费用标准，跳过", shopId);
                        failCount++;
                        continue;
                    }
                    
                    // 创建费用记录
                    ShopFeeRecord feeRecord = new ShopFeeRecord();
                    feeRecord.setShopId(shopId);
                    feeRecord.setFeeType(dto.getFeeType());
                    feeRecord.setFeeAmount(feeAmount);
                    feeRecord.setFeePeriod(dto.getBatchMonth());
                    feeRecord.setFeeStartDate(monthStart);
                    feeRecord.setFeeEndDate(monthEnd);
                    feeRecord.setPaymentStatus(dto.getPaymentStatus());
                    feeRecord.setRemark(dto.getRemark());
                    
                    // 设置创建人
                    Long currentUserId = SecurityUtils.getCurrentUserId();
                    feeRecord.setCreateBy(currentUserId);
                    feeRecord.setUpdateBy(currentUserId);
                    
                    // 保存费用记录
                    boolean success = save(feeRecord);
                    if (success) {
                        generatedIds.add(feeRecord.getId());
                        successCount++;
                        log.info("为店铺{}生成费用记录成功，ID: {}", shopId, feeRecord.getId());
                    } else {
                        failCount++;
                        log.warn("为店铺{}生成费用记录失败", shopId);
                    }
                    
                } catch (Exception e) {
                    failCount++;
                    log.error("为店铺{}生成费用记录失败", shopId, e);
                }
            }
            
            // 构建返回结果
            Map<String, Object> result = new HashMap<>();
            result.put("totalShops", dto.getShopIds().size());
            result.put("successCount", successCount);
            result.put("failCount", failCount);
            result.put("generatedIds", generatedIds);
            
            log.info("批量生成费用记录完成，总店铺数: {}, 成功: {}, 失败: {}", 
                    dto.getShopIds().size(), successCount, failCount);
            
            return result;
            
        } catch (Exception e) {
            log.error("批量生成费用记录失败，店铺数量: {}, 费用类型: {}, 生成月份: {}", 
                    dto.getShopIds().size(), dto.getFeeType(), dto.getBatchMonth(), e);
            throw new Exception("批量生成费用记录失败: " + e.getMessage());
        }
    }
    
    /**
     * 更新费用记录
     * 遵循《Java后端SpringBoot代码开发规范_重构版.md》Service层规范
     */
    @Override
    @GlobalTransactional(rollbackFor = Exception.class)
    @CacheEvict(value = {"feeRecord:page", "feeRecord:detail"}, allEntries = true)
    public Boolean updateFeeRecord(Long id, ShopFeeRecordDTO dto) throws Exception {
        log.info("更新费用记录，ID: {}, 店铺ID: {}, 费用类型: {}", 
                id, dto.getShopId(), dto.getFeeType());
        
        try {
            // 检查费用记录是否存在
            ShopFeeRecord existingRecord = getById(id);
            if (existingRecord == null) {
                throw new Exception("费用记录不存在");
            }
            
            // 更新费用记录
            BeanUtils.copyProperties(dto, existingRecord);
            existingRecord.setId(id);
            
            // 设置更新人
            Long currentUserId = SecurityUtils.getCurrentUserId();
            existingRecord.setUpdateBy(currentUserId);
            
            boolean success = updateById(existingRecord);
            if (!success) {
                throw new Exception("更新费用记录失败");
            }
            
            log.info("更新费用记录成功，ID: {}", id);
            return true;
            
        } catch (Exception e) {
            log.error("更新费用记录失败，ID: {}, 店铺ID: {}, 费用类型: {}", 
                    id, dto.getShopId(), dto.getFeeType(), e);
            throw new Exception("更新费用记录失败: " + e.getMessage());
        }
    }
    
    /**
     * 删除费用记录
     * 遵循《Java后端SpringBoot代码开发规范_重构版.md》Service层规范
     */
    @Override
    @GlobalTransactional(rollbackFor = Exception.class)
    @CacheEvict(value = {"feeRecord:page", "feeRecord:detail"}, allEntries = true)
    public Boolean deleteFeeRecord(Long id) throws Exception {
        log.info("删除费用记录，ID: {}", id);
        
        try {
            // 检查费用记录是否存在
            ShopFeeRecord existingRecord = getById(id);
            if (existingRecord == null) {
                throw new Exception("费用记录不存在");
            }
            
            // 删除费用记录
            boolean success = removeById(id);
            if (!success) {
                throw new Exception("删除费用记录失败");
            }
            
            log.info("删除费用记录成功，ID: {}", id);
            return true;
            
        } catch (Exception e) {
            log.error("删除费用记录失败，ID: {}", id, e);
            throw new Exception("删除费用记录失败: " + e.getMessage());
        }
    }
    
    /**
     * 批量删除费用记录
     * 遵循《Java后端SpringBoot代码开发规范_重构版.md》Service层规范
     */
    @Override
    @GlobalTransactional(rollbackFor = Exception.class)
    @CacheEvict(value = {"feeRecord:page", "feeRecord:detail"}, allEntries = true)
    public Boolean batchDeleteFeeRecords(List<Long> ids) throws Exception {
        log.info("批量删除费用记录，数量: {}", ids.size());
        
        try {
            if (CollectionUtils.isEmpty(ids)) {
                throw new Exception("费用记录ID列表不能为空");
            }
            
            // 批量删除费用记录
            boolean success = removeByIds(ids);
            if (!success) {
                throw new Exception("批量删除费用记录失败");
            }
            
            log.info("批量删除费用记录成功，数量: {}", ids.size());
            return true;
            
        } catch (Exception e) {
            log.error("批量删除费用记录失败，数量: {}", ids.size(), e);
            throw new Exception("批量删除费用记录失败: " + e.getMessage());
        }
    }
    
    /**
     * 获取店铺的费用金额
     * 遵循《Java后端SpringBoot代码开发规范_重构版.md》Service层规范
     * 支持前端枚举值：STANDARD-按费用标准生成，CUSTOM-自定义金额
     * 兼容后端原有枚举值：AUTO-自动生成，MANUAL-手动生成
     */
    private BigDecimal getFeeAmountForShop(Long shopId, String feeType, String batchMode, BigDecimal customAmount) {
        try {
            // 处理自定义金额模式（前端：CUSTOM，后端：MANUAL）
            if ("CUSTOM".equals(batchMode) || "MANUAL".equals(batchMode)) {
                if (customAmount != null && customAmount.compareTo(BigDecimal.ZERO) > 0) {
                    return customAmount;
                } else {
                    log.warn("店铺{}自定义金额模式但未提供有效金额，费用类型: {}", shopId, feeType);
                    return null;
                }
            }
            
            // 处理按费用标准生成模式（前端：STANDARD，后端：AUTO）
            if ("STANDARD".equals(batchMode) || "AUTO".equals(batchMode)) {
                // 查询店铺的费用标准
                // TODO: 实现根据费用标准获取金额的逻辑
                // 这里需要调用费用标准服务获取当前有效的费用标准
                // 临时返回固定金额，实际应该查询费用标准表
                log.info("按费用标准生成模式，店铺ID: {}, 费用类型: {}", shopId, feeType);
                return BigDecimal.valueOf(1000.00); // 临时返回固定金额
            }
            
            log.warn("未知的生成方式: {}, 店铺ID: {}, 费用类型: {}", batchMode, shopId, feeType);
            return null;
            
        } catch (Exception e) {
            log.error("获取店铺{}费用金额失败，费用类型: {}, 生成方式: {}", shopId, feeType, batchMode, e);
            return null;
        }
    }
    
    /**
     * 根据社区ID列表查询店铺ID列表
     * 遵循《Java后端SpringBoot代码开发规范_重构版.md》Service层规范
     * 遵循《系统状态枚举权威标准声明.md》状态枚举规范
     * 
     * @param communityIds 社区ID列表
     * @return 店铺ID列表
     */
    private List<Long> getShopIdsByCommunityIds(List<Long> communityIds) {
        try {
            // 参数校验
            if (communityIds == null || communityIds.isEmpty()) {
                log.warn("社区ID列表为空，返回空店铺ID列表");
                return Collections.emptyList();
            }
            
            log.info("根据社区ID列表查询店铺ID列表，社区数量: {}", communityIds.size());
            
            // 使用IN语句直接查询，避免循环调用
            List<Shop> shops = shopService.list(
                new QueryWrapper<Shop>()
                    .in("community_id", communityIds)
                    .eq("deleted", 0)
                    .select("id")
            );
            
            // 提取店铺ID列表
            List<Long> shopIds = shops.stream()
                    .map(Shop::getId)
                    .filter(id -> id != null)
                    .collect(java.util.stream.Collectors.toList());
            
            log.info("根据社区ID列表查询店铺ID列表成功，社区数量: {}, 店铺数量: {}", 
                    communityIds.size(), shopIds.size());
            
            return shopIds;
            
        } catch (Exception e) {
            log.error("根据社区ID列表查询店铺ID失败，社区ID列表: {}", communityIds, e);
            return Collections.emptyList();
        }
    }
    
    /**
     * 创建空的分页结果
     * 遵循《Java后端SpringBoot代码开发规范_重构版.md》Service层规范
     */
    private Object createEmptyPageResult(Integer current, Integer size) {
        Page<ShopFeeRecordVO> page = new Page<>(current, size);
        page.setTotal(0);
        page.setRecords(new ArrayList<>());
        return page;
    }
    
    /**
     * 获取费用统计信息
     * 遵循《Java后端SpringBoot代码开发规范_重构版.md》Service层规范
     * 遵循《系统状态枚举权威标准声明.md》状态枚举规范
     */
    @Override
    @Cacheable(value = "feeRecord:statistics", key = "#currentUserId + '_' + #shopId + '_' + #feeType + '_' + #paymentStatus")
    public Object getFeeStatistics(Long shopId, String feeType, Integer paymentStatus) throws Exception {
        log.info("获取费用统计信息，店铺ID: {}, 费用类型: {}, 支付状态: {}", shopId, feeType, paymentStatus);
        
        try {
            // 获取当前用户ID
            Long currentUserId = SecurityUtils.getCurrentUserId();
            if (currentUserId == null) {
                log.warn("用户未登录，无法获取费用统计信息");
                return createEmptyStatistics();
            }
            
            // 获取用户数据权限范围
            DataScopeInfo userDataScope = dataScopeFeign.getUserDataScope(currentUserId);
            if (userDataScope == null) {
                log.warn("获取用户数据权限范围失败，用户ID：{}，返回空统计结果", currentUserId);
                return createEmptyStatistics();
            }
            
            log.info("用户数据权限信息：用户ID={}, 是否超级管理员={}, 是否物业公司用户={}, 社区ID列表={}", 
                currentUserId, userDataScope.isSuperAdmin(), userDataScope.isPropertyCompanyUser(), userDataScope.getCommunityIds());
            
            // 构建统计查询条件
            Map<String, Object> statistics = new HashMap<>();
            
            if (userDataScope.isSuperAdmin()) {
                // 超级管理员可以查看所有统计数据
                log.info("用户{}为超级管理员，可以查看所有费用统计", currentUserId);
                statistics = baseMapper.getFeeStatistics(shopId, feeType, paymentStatus);
            } else {
                // 物业公司用户只能查看关联社区的统计数据
                List<Long> communityIds = userDataScope.getCommunityIds();
                if (communityIds == null || communityIds.isEmpty()) {
                    log.warn("用户{}无权限访问任何社区数据，返回空统计结果", currentUserId);
                    statistics = createEmptyStatistics();
                } else {
                    // 根据社区ID列表查询店铺ID列表
                    List<Long> shopIds = getShopIdsByCommunityIds(communityIds);
                    if (shopIds.isEmpty()) {
                        log.warn("用户{}关联的社区{}中没有店铺数据，返回空统计结果", currentUserId, communityIds);
                        statistics = createEmptyStatistics();
                    } else {
                        // 使用带权限过滤的统计查询方法
                        statistics = baseMapper.getFeeStatisticsByShopIds(shopIds, feeType, paymentStatus);
                        log.info("用户{}数据权限过滤完成，可访问店铺数量：{}，店铺IDs：{}", currentUserId, shopIds.size(), shopIds);
                    }
                }
            }
            
            // 确保统计结果包含所有必要字段
            ensureStatisticsFields(statistics);
            
            log.info("获取费用统计信息成功，统计结果: {}", statistics);
            return statistics;
            
        } catch (Exception e) {
            log.error("获取费用统计信息失败，店铺ID: {}, 费用类型: {}, 支付状态: {}", shopId, feeType, paymentStatus, e);
            throw new Exception("获取费用统计信息失败: " + e.getMessage());
        }
    }
    
    /**
     * 支付费用记录
     * 遵循《Java后端SpringBoot代码开发规范_重构版.md》Service层规范
     */
    @Override
    @GlobalTransactional(rollbackFor = Exception.class)
    @CacheEvict(value = {"feeRecord:page", "feeRecord:detail", "feeRecord:statistics"}, allEntries = true)
    public Boolean payFeeRecord(Long id, Map<String, Object> paymentInfo) throws Exception {
        log.info("支付费用记录，ID: {}, 支付信息: {}", id, paymentInfo);
        
        try {
            // 检查费用记录是否存在
            ShopFeeRecord existingRecord = getById(id);
            if (existingRecord == null) {
                throw new Exception("费用记录不存在");
            }
            
            // 检查是否已经支付
            if (existingRecord.getPaymentStatus() == 1) {
                throw new Exception("费用记录已经支付，不能重复支付");
            }
            
            // 更新支付信息
            ShopFeeRecord updateRecord = new ShopFeeRecord();
            updateRecord.setId(id);
            updateRecord.setPaymentStatus(1); // 已支付
            updateRecord.setPaymentDate(LocalDateTime.now());
            updateRecord.setPaymentMethod((String) paymentInfo.get("paymentMethod"));
            updateRecord.setInvoiceNumber((String) paymentInfo.get("receiptNumber"));
            updateRecord.setRemark((String) paymentInfo.get("remark"));
            
            boolean success = updateById(updateRecord);
            if (!success) {
                throw new Exception("支付费用记录失败");
            }
            
            log.info("支付费用记录成功，ID: {}", id);
            return true;
            
        } catch (Exception e) {
            log.error("支付费用记录失败，ID: {}, 支付信息: {}", id, paymentInfo, e);
            throw new Exception("支付费用记录失败: " + e.getMessage());
        }
    }
    
    /**
     * 批量支付费用记录
     * 遵循《Java后端SpringBoot代码开发规范_重构版.md》Service层规范
     */
    @Override
    @GlobalTransactional(rollbackFor = Exception.class)
    @CacheEvict(value = {"feeRecord:page", "feeRecord:detail", "feeRecord:statistics"}, allEntries = true)
    public Boolean batchPayFeeRecords(List<Long> ids, Map<String, Object> paymentInfo) throws Exception {
        log.info("批量支付费用记录，数量: {}, 支付信息: {}", ids.size(), paymentInfo);
        
        try {
            if (CollectionUtils.isEmpty(ids)) {
                throw new Exception("费用记录ID列表不能为空");
            }
            
            // 检查所有费用记录是否存在且未支付
            List<ShopFeeRecord> existingRecords = listByIds(ids);
            if (existingRecords.size() != ids.size()) {
                throw new Exception("部分费用记录不存在");
            }
            
            for (ShopFeeRecord record : existingRecords) {
                if (record.getPaymentStatus() == 1) {
                    throw new Exception("费用记录ID " + record.getId() + " 已经支付，不能重复支付");
                }
            }
            
            // 批量更新支付信息
            List<ShopFeeRecord> updateRecords = new ArrayList<>();
            for (Long id : ids) {
                ShopFeeRecord updateRecord = new ShopFeeRecord();
                updateRecord.setId(id);
                updateRecord.setPaymentStatus(1); // 已支付
                updateRecord.setPaymentDate(LocalDateTime.now());
                updateRecord.setPaymentMethod((String) paymentInfo.get("paymentMethod"));
                updateRecord.setInvoiceNumber((String) paymentInfo.get("receiptNumber"));
                updateRecord.setRemark((String) paymentInfo.get("remark"));
                updateRecords.add(updateRecord);
            }
            
            boolean success = updateBatchById(updateRecords);
            if (!success) {
                throw new Exception("批量支付费用记录失败");
            }
            
            log.info("批量支付费用记录成功，数量: {}", ids.size());
            return true;
            
        } catch (Exception e) {
            log.error("批量支付费用记录失败，数量: {}, 支付信息: {}", ids.size(), paymentInfo, e);
            throw new Exception("批量支付费用记录失败: " + e.getMessage());
        }
    }
    
    /**
     * 催缴费用记录
     * 遵循《Java后端SpringBoot代码开发规范_重构版.md》Service层规范
     */
    @Override
    @GlobalTransactional(rollbackFor = Exception.class)
    @CacheEvict(value = {"feeRecord:page", "feeRecord:detail"}, allEntries = true)
    public Boolean remindFeeRecord(Long id) throws Exception {
        log.info("催缴费用记录，ID: {}", id);
        
        try {
            // 检查费用记录是否存在
            ShopFeeRecord existingRecord = getById(id);
            if (existingRecord == null) {
                throw new Exception("费用记录不存在");
            }
            
            // 检查是否已经支付
            if (existingRecord.getPaymentStatus() == 1) {
                throw new Exception("费用记录已经支付，无需催缴");
            }
            
            // 更新催缴信息
            ShopFeeRecord updateRecord = new ShopFeeRecord();
            updateRecord.setId(id);
            updateRecord.setRemark("已发送催缴通知 - " + LocalDate.now());
            
            boolean success = updateById(updateRecord);
            if (!success) {
                throw new Exception("催缴费用记录失败");
            }
            
            // TODO: 这里可以添加发送催缴通知的逻辑
            // 比如发送短信、邮件、微信通知等
            
            log.info("催缴费用记录成功，ID: {}", id);
            return true;
            
        } catch (Exception e) {
            log.error("催缴费用记录失败，ID: {}", id, e);
            throw new Exception("催缴费用记录失败: " + e.getMessage());
        }
    }
    
    /**
     * 批量催缴费用记录
     * 遵循《Java后端SpringBoot代码开发规范_重构版.md》Service层规范
     */
    @Override
    @GlobalTransactional(rollbackFor = Exception.class)
    @CacheEvict(value = {"feeRecord:page", "feeRecord:detail"}, allEntries = true)
    public Boolean batchRemindFeeRecords(List<Long> ids) throws Exception {
        log.info("批量催缴费用记录，数量: {}", ids.size());
        
        try {
            if (CollectionUtils.isEmpty(ids)) {
                throw new Exception("费用记录ID列表不能为空");
            }
            
            // 检查所有费用记录是否存在且未支付
            List<ShopFeeRecord> existingRecords = listByIds(ids);
            if (existingRecords.size() != ids.size()) {
                throw new Exception("部分费用记录不存在");
            }
            
            for (ShopFeeRecord record : existingRecords) {
                if (record.getPaymentStatus() == 1) {
                    throw new Exception("费用记录ID " + record.getId() + " 已经支付，无需催缴");
                }
            }
            
            // 批量更新催缴信息
            List<ShopFeeRecord> updateRecords = new ArrayList<>();
            for (Long id : ids) {
                ShopFeeRecord updateRecord = new ShopFeeRecord();
                updateRecord.setId(id);
                updateRecord.setRemark("已发送催缴通知 - " + LocalDate.now());
                updateRecords.add(updateRecord);
            }
            
            boolean success = updateBatchById(updateRecords);
            if (!success) {
                throw new Exception("批量催缴费用记录失败");
            }
            
            // TODO: 这里可以添加批量发送催缴通知的逻辑
            
            log.info("批量催缴费用记录成功，数量: {}", ids.size());
            return true;
            
        } catch (Exception e) {
            log.error("批量催缴费用记录失败，数量: {}", ids.size(), e);
            throw new Exception("批量催缴费用记录失败: " + e.getMessage());
        }
    }
    
    /**
     * 导出费用记录
     * 遵循《Java后端SpringBoot代码开发规范_重构版.md》Service层规范
     */
    @Override
    public String exportFeeRecords(Long shopId, String feeType, Integer paymentStatus) throws Exception {
        log.info("导出费用记录，店铺ID: {}, 费用类型: {}, 支付状态: {}", shopId, feeType, paymentStatus);
        
        try {
            // 获取当前用户ID
            Long currentUserId = SecurityUtils.getCurrentUserId();
            if (currentUserId == null) {
                throw new Exception("用户未登录");
            }
            
            // 获取用户数据权限范围
            DataScopeInfo userDataScope = dataScopeFeign.getUserDataScope(currentUserId);
            if (userDataScope == null) {
                throw new Exception("获取用户数据权限范围失败");
            }
            
            // 构建导出查询条件
            List<ShopFeeRecordVO> exportData;
            
            if (userDataScope.isSuperAdmin()) {
                // 超级管理员可以导出所有数据
                exportData = baseMapper.selectFeeRecordVOList(shopId, feeType, paymentStatus);
            } else {
                // 物业公司用户只能导出关联社区的数据
                List<Long> communityIds = userDataScope.getCommunityIds();
                if (communityIds == null || communityIds.isEmpty()) {
                    exportData = new ArrayList<>();
                } else {
                    List<Long> shopIds = getShopIdsByCommunityIds(communityIds);
                    if (shopIds.isEmpty()) {
                        exportData = new ArrayList<>();
                    } else {
                        exportData = baseMapper.selectFeeRecordVOListByShopIds(shopIds, feeType, paymentStatus);
                    }
                }
            }
            
            // TODO: 实现Excel导出逻辑
            // 这里可以使用EasyExcel或其他Excel工具类进行导出
            String fileName = "费用记录_" + LocalDate.now() + ".xlsx";
            
            log.info("导出费用记录成功，文件名: {}, 数据量: {}", fileName, exportData.size());
            return fileName;
            
        } catch (Exception e) {
            log.error("导出费用记录失败，店铺ID: {}, 费用类型: {}, 支付状态: {}", shopId, feeType, paymentStatus, e);
            throw new Exception("导出费用记录失败: " + e.getMessage());
        }
    }
    
    /**
     * 创建空的统计信息
     * 遵循《Java后端SpringBoot代码开发规范_重构版.md》Service层规范
     * 遵循《系统状态枚举权威标准声明.md》状态枚举规范
     */
    private Map<String, Object> createEmptyStatistics() {
        Map<String, Object> statistics = new HashMap<>();
        statistics.put("totalAmount", BigDecimal.ZERO);
        statistics.put("paidAmount", BigDecimal.ZERO);
        statistics.put("unpaidAmount", BigDecimal.ZERO);
        statistics.put("overdueAmount", BigDecimal.ZERO);
        statistics.put("totalCount", 0L);
        statistics.put("paidCount", 0L);
        statistics.put("unpaidCount", 0L);
        statistics.put("overdueCount", 0L);
        return statistics;
    }
    
    /**
     * 确保统计结果包含所有必要字段
     * 遵循《Java后端SpringBoot代码开发规范_重构版.md》Service层规范
     * 遵循《系统状态枚举权威标准声明.md》状态枚举规范
     */
    private void ensureStatisticsFields(Map<String, Object> statistics) {
        if (statistics == null) {
            statistics = new HashMap<>();
        }
        
        // 确保金额字段存在且为BigDecimal类型
        statistics.putIfAbsent("totalAmount", BigDecimal.ZERO);
        statistics.putIfAbsent("paidAmount", BigDecimal.ZERO);
        statistics.putIfAbsent("unpaidAmount", BigDecimal.ZERO);
        statistics.putIfAbsent("overdueAmount", BigDecimal.ZERO);
        
        // 确保数量字段存在且为Long类型（与数据库返回类型一致）
        statistics.putIfAbsent("totalCount", 0L);
        statistics.putIfAbsent("paidCount", 0L);
        statistics.putIfAbsent("unpaidCount", 0L);
        statistics.putIfAbsent("overdueCount", 0L);
        
        // 转换数据库返回的字段名到标准字段名
        if (statistics.containsKey("total_amount")) {
            statistics.put("totalAmount", statistics.get("total_amount"));
        }
        if (statistics.containsKey("paid_amount")) {
            statistics.put("paidAmount", statistics.get("paid_amount"));
        }
        if (statistics.containsKey("unpaid_amount")) {
            statistics.put("unpaidAmount", statistics.get("unpaid_amount"));
        }
        if (statistics.containsKey("overdue_amount")) {
            statistics.put("overdueAmount", statistics.get("overdue_amount"));
        }
        if (statistics.containsKey("total_count")) {
            statistics.put("totalCount", statistics.get("total_count"));
        }
        if (statistics.containsKey("paid_count")) {
            statistics.put("paidCount", statistics.get("paid_count"));
        }
        if (statistics.containsKey("unpaid_count")) {
            statistics.put("unpaidCount", statistics.get("unpaid_count"));
        }
        if (statistics.containsKey("overdue_count")) {
            statistics.put("overdueCount", statistics.get("overdue_count"));
        }
        
        // 计算支付率
        Number totalCountNum = (Number) statistics.get("totalCount");
        Number paidCountNum = (Number) statistics.get("paidCount");
        if (totalCountNum != null && totalCountNum.longValue() > 0 && paidCountNum != null) {
            double paymentRate = (double) paidCountNum.longValue() / totalCountNum.longValue() * 100;
            statistics.put("paymentRate", Math.round(paymentRate * 100.0) / 100.0);
        } else {
            statistics.put("paymentRate", 0.0);
        }
        
        // 计算逾期率
        Number overdueCountNum = (Number) statistics.get("overdueCount");
        if (totalCountNum != null && totalCountNum.longValue() > 0 && overdueCountNum != null) {
            double overdueRate = (double) overdueCountNum.longValue() / totalCountNum.longValue() * 100;
            statistics.put("overdueRate", Math.round(overdueRate * 100.0) / 100.0);
        } else {
            statistics.put("overdueRate", 0.0);
        }
    }
}
